﻿using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Text;
using System.Drawing.Design;
using System.Reflection;
using System.Windows.Forms.Design;
using System.Windows.Forms;
using System.Globalization;
//MicroDesigner
using Jc.MicroDesigner.Management;
using Jc.MicroDesigner.ToolWindows;

namespace Jc.MicroDesigner.Objects
{
    /* Классы для простого отображения и редактирования пинов для схем-контейнеров */

    /// <summary>
    /// Служебный класс для отображения и редактирования информации о шлюзах
    /// </summary>
    public class CompositeView
    {
        List<GateView> _Views = new List<GateView>();

        /// <summary>
        /// Имя
        /// </summary>
        public string Name
        {
            get;
            set;
        }

        /// <summary>
        /// Описание
        /// </summary>
        public string Description
        {
            get;
            set;
        }

        /// <summary>
        /// Файл изображения
        /// </summary>
        public string ImgPath
        {
            get;
            set;
        }

        /// <summary>
        /// Шлюзы
        /// </summary>
        public List<GateView> Views
        {
            get { return _Views; }
        }

        /// <summary>
        /// Создать отображение
        /// </summary>
        public CompositeView()
        {
            Name = "Element";
            Description = "";
            ImgPath = "";
        }
    }

    /// <summary>
    /// Вспомогательный класс для формы выбора пинов
    /// </summary>
    public class PINGate
    {
        /// <summary>
        /// Схема
        /// </summary>
        public ObjectManager Manager
        {
            get;
            set;
        }

        /// <summary>
        /// Выбранный пин
        /// </summary>
        public PIN SelectedPin
        {
            get;
            set;
        }

        /// <summary>
        /// Создать отображение шлюза
        /// </summary>
        /// <param name="manager"></param>
        public PINGate(ObjectManager manager)
        {
            SelectedPin = null;
            Manager = manager;
        }
    }

    /// <summary>
    /// Отображение шлюза
    /// </summary>
    public class GateView
    {
        PINGate _InnerPIN = null;

        /// <summary>
        /// Внутренний пин
        /// </summary>
        [DisplayName("Внутренний пин схемы")]
        [Category("Устройство")]
        [TypeConverter(typeof(PINGatePropertyConverter))]
        [Editor(typeof(PINGatePropertyEditor), typeof(UITypeEditor))]
        public PINGate InnerPIN
        {
            get { return _InnerPIN; }
            set { _InnerPIN = value; }
        }

        /// <summary>
        /// Тип пина
        /// </summary>
        [DisplayName("Тип внешнего пина")]
        [Category("Устройство")]
        [TypeConverter(typeof(EnumTypeConverter))]
        public PINType PinType
        {
            get;
            set;
        }

        /// <summary>
        /// Отступ слева
        /// </summary>
        [DisplayName("X координата области")]
        [Category("Область рисования")]
        public int Left
        {
            get;
            set;
        }

        /// <summary>
        /// Отступ сверху
        /// </summary>
        [DisplayName("Y координата области")]
        [Category("Область рисования")]
        public int Top
        {
            get;
            set;
        }

        /// <summary>
        /// X точки контакта
        /// </summary>
        [DisplayName("X точки контакта")]
        [Category("Соединение")]
        public int BindX
        {
            get;
            set;
        }

        /// <summary>
        /// Y точки контакта
        /// </summary>
        [DisplayName("Y точки контакта")]
        [Category("Соединение")]
        public int BindY
        {
            get;
            set;
        }

        /// <summary>
        /// Ширина области
        /// </summary>
        [DisplayName("Ширина области")]
        [Category("Область рисования")]
        public int Width
        {
            get;
            set;
        }

        /// <summary>
        /// Высота области
        /// </summary>
        [DisplayName("Высота области")]
        [Category("Область рисования")]
        public int Height
        {
            get;
            set;
        }

        /// <summary>
        /// Создать отображение для шлюза
        /// </summary>
        /// <param name="manager"></param>
        public GateView(ObjectManager manager)
        {
            _InnerPIN = new PINGate(manager);
            PinType = PINType.Other;
            Left = 0;
            Top = 0;
            Width = 0;
            Height = 0;
            BindX = 0;
            BindY = 0;
        }
    }

    /// <summary>
    /// Редактор свойств с вызовом требуемой формы
    /// </summary>
    public class PINGatePropertyEditor : UITypeEditor
    {
        /// <summary>
        /// Реализация метода редактирования
        /// </summary>
        public override Object EditValue(
          ITypeDescriptorContext context,
          IServiceProvider provider,
          Object value)
        {
            if ((context != null) && (provider != null))
            {
                IWindowsFormsEditorService svc =
                  (IWindowsFormsEditorService)
                  provider.GetService(typeof(IWindowsFormsEditorService));

                if (svc != null)
                {
                    if (value != null)
                    {
                        PINGate pgate = value as PINGate;
                        PINSelectForm form = new PINSelectForm();
                        if (form.ShowDialog(pgate.Manager) == DialogResult.OK)
                        {
                            pgate.SelectedPin = form.SelectedPIN;
                        }
                    }
                }
            }

            return value;
        }

        /// <summary>
        /// Возвращаем стиль редактора - модальное окно
        /// </summary>
        public override UITypeEditorEditStyle GetEditStyle(
          ITypeDescriptorContext context)
        {
            if (context != null)
                return UITypeEditorEditStyle.Modal;
            else
                return base.GetEditStyle(context);
        }
    }

    /// <summary>
    /// Конвертер для свойств
    /// </summary>
    public class PINGatePropertyConverter : TypeConverter
    {
        /// <summary>
        /// Приведение к строковому типу для PIN
        /// </summary>
        /// <param name="context">Контекст</param>
        /// <param name="culture">Культура</param>
        /// <param name="value">Значение</param>
        /// <param name="destType">Новый тип</param>
        /// <returns>Значение</returns>
        public override object ConvertTo(ITypeDescriptorContext context,
          CultureInfo culture,
          object value,
          Type destType)
        {
            PIN p = (value as PINGate).SelectedPin;
            if (p != null)
                return p.Parent.Name + " | " + p.Name;
            else
                return "Не выбран";
        }

        /// <summary>
        /// Возможно конвертировать в строку
        /// </summary>
        /// <param name="context">Контекст</param>
        /// <param name="destinationType">Тип для приведения</param>
        /// <returns>Результат</returns>
        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(string))
                return true;
            return base.CanConvertTo(context, destinationType);
        }
    }

    /// <summary>
    /// TypeConverter для Enum, преобразовывающий Enum к строке с
    /// учетом атрибута Description
    /// </summary>
    class EnumTypeConverter : EnumConverter
    {
        private Type _enumType;
        /// <summary>Инициализирует экземпляр</summary>
        /// <param name="type">тип Enum</param>
        public EnumTypeConverter(Type type)
            : base(type)
        {
            _enumType = type;
        }

        public override bool CanConvertTo(ITypeDescriptorContext context,
          Type destType)
        {
            return destType == typeof(string);
        }

        public override object ConvertTo(ITypeDescriptorContext context,
          CultureInfo culture,
          object value, Type destType)
        {
            FieldInfo fi = _enumType.GetField(Enum.GetName(_enumType, value));
            DescriptionAttribute dna =
              (DescriptionAttribute)Attribute.GetCustomAttribute(
                fi, typeof(DescriptionAttribute));

            if (dna != null)
                return dna.Description;
            else
                return value.ToString();
        }

        public override bool CanConvertFrom(ITypeDescriptorContext context,
          Type srcType)
        {
            return srcType == typeof(string);
        }

        public override object ConvertFrom(ITypeDescriptorContext context,
          CultureInfo culture,
          object value)
        {
            foreach (FieldInfo fi in _enumType.GetFields())
            {
                DescriptionAttribute dna =
                  (DescriptionAttribute)Attribute.GetCustomAttribute(
                    fi, typeof(DescriptionAttribute));

                if ((dna != null) && ((string)value == dna.Description))
                    return Enum.Parse(_enumType, fi.Name);
            }

            return Enum.Parse(_enumType, (string)value);
        }

    }
}